home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / lib / python2.4 / compiler / pyassem.pyo (.txt) < prev    next >
Python Compiled Bytecode  |  2005-10-18  |  26KB  |  924 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.4)
  3.  
  4. '''A flow graph representation for Python bytecode'''
  5. import dis
  6. import new
  7. import sys
  8. import types
  9. from compiler import misc
  10. from compiler.consts import CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS
  11.  
  12. class FlowGraph:
  13.     
  14.     def __init__(self):
  15.         self.current = self.entry = Block()
  16.         self.exit = Block('exit')
  17.         self.blocks = misc.Set()
  18.         self.blocks.add(self.entry)
  19.         self.blocks.add(self.exit)
  20.  
  21.     
  22.     def startBlock(self, block):
  23.         if self._debug:
  24.             if self.current:
  25.                 print 'end', repr(self.current)
  26.                 print '    next', self.current.next
  27.                 print '   ', self.current.get_children()
  28.             
  29.             print repr(block)
  30.         
  31.         self.current = block
  32.  
  33.     
  34.     def nextBlock(self, block = None):
  35.         if block is None:
  36.             block = self.newBlock()
  37.         
  38.         self.current.addNext(block)
  39.         self.startBlock(block)
  40.  
  41.     
  42.     def newBlock(self):
  43.         b = Block()
  44.         self.blocks.add(b)
  45.         return b
  46.  
  47.     
  48.     def startExitBlock(self):
  49.         self.startBlock(self.exit)
  50.  
  51.     _debug = 0
  52.     
  53.     def _enable_debug(self):
  54.         self._debug = 1
  55.  
  56.     
  57.     def _disable_debug(self):
  58.         self._debug = 0
  59.  
  60.     
  61.     def emit(self, *inst):
  62.         if self._debug:
  63.             print '\t', inst
  64.         
  65.         if inst[0] in [
  66.             'RETURN_VALUE',
  67.             'YIELD_VALUE']:
  68.             self.current.addOutEdge(self.exit)
  69.         
  70.         if len(inst) == 2 and isinstance(inst[1], Block):
  71.             self.current.addOutEdge(inst[1])
  72.         
  73.         self.current.emit(inst)
  74.  
  75.     
  76.     def getBlocksInOrder(self):
  77.         '''Return the blocks in reverse postorder
  78.  
  79.         i.e. each node appears before all of its successors
  80.         '''
  81.         for b in self.blocks.elements():
  82.             if b is self.exit:
  83.                 continue
  84.             
  85.             if not b.next:
  86.                 b.addNext(self.exit)
  87.                 continue
  88.         
  89.         order = dfs_postorder(self.entry, { })
  90.         order.reverse()
  91.         self.fixupOrder(order, self.exit)
  92.         if self.exit not in order:
  93.             order.append(self.exit)
  94.         
  95.         return order
  96.  
  97.     
  98.     def fixupOrder(self, blocks, default_next):
  99.         '''Fixup bad order introduced by DFS.'''
  100.         self.fixupOrderHonorNext(blocks, default_next)
  101.         self.fixupOrderForward(blocks, default_next)
  102.  
  103.     
  104.     def fixupOrderHonorNext(self, blocks, default_next):
  105.         '''Fix one problem with DFS.
  106.  
  107.         The DFS uses child block, but doesn\'t know about the special
  108.         "next" block.  As a result, the DFS can order blocks so that a
  109.         block isn\'t next to the right block for implicit control
  110.         transfers.
  111.         '''
  112.         index = { }
  113.         for i in range(len(blocks)):
  114.             index[blocks[i]] = i
  115.         
  116.         for i in range(0, len(blocks) - 1):
  117.             b = blocks[i]
  118.             n = blocks[i + 1]
  119.             if not (b.next) and b.next[0] == default_next or b.next[0] == n:
  120.                 continue
  121.             
  122.             cur = b
  123.             chain = []
  124.             elt = cur
  125.             while elt.next and elt.next[0] != default_next:
  126.                 chain.append(elt.next[0])
  127.                 elt = elt.next[0]
  128.             l = []
  129.             for b in chain:
  130.                 l.append((index[b], b))
  131.             
  132.             l.sort()
  133.             l.reverse()
  134.             for j, b in l:
  135.                 del blocks[index[b]]
  136.             
  137.             blocks[i:i + 1] = [
  138.                 cur] + chain
  139.             for i in range(len(blocks)):
  140.                 index[blocks[i]] = i
  141.             
  142.         
  143.  
  144.     
  145.     def fixupOrderForward(self, blocks, default_next):
  146.         '''Make sure all JUMP_FORWARDs jump forward'''
  147.         index = { }
  148.         chains = []
  149.         cur = []
  150.         for b in blocks:
  151.             index[b] = len(chains)
  152.             cur.append(b)
  153.             if b.next and b.next[0] == default_next:
  154.                 chains.append(cur)
  155.                 cur = []
  156.                 continue
  157.         
  158.         chains.append(cur)
  159.         while None:
  160.             constraints = []
  161.             for i in range(len(chains)):
  162.                 l = chains[i]
  163.                 for b in l:
  164.                     for c in b.get_children():
  165.                         if index[c] < i:
  166.                             forward_p = 0
  167.                             for inst in b.insts:
  168.                                 if inst[0] == 'JUMP_FORWARD':
  169.                                     if inst[1] == c:
  170.                                         forward_p = 1
  171.                                     
  172.                                 inst[1] == c
  173.                             
  174.                             if not forward_p:
  175.                                 continue
  176.                             
  177.                             constraints.append((index[c], i))
  178.                             continue
  179.                     
  180.                 
  181.             
  182.             if not constraints:
  183.                 break
  184.             
  185.             (goes_before, a_chain) = constraints[0]
  186.             c = chains[a_chain]
  187.             chains.insert(goes_before, c)
  188.         del blocks[:]
  189.         for c in chains:
  190.             for b in c:
  191.                 blocks.append(b)
  192.             
  193.         
  194.  
  195.     
  196.     def getBlocks(self):
  197.         return self.blocks.elements()
  198.  
  199.     
  200.     def getRoot(self):
  201.         '''Return nodes appropriate for use with dominator'''
  202.         return self.entry
  203.  
  204.     
  205.     def getContainedGraphs(self):
  206.         l = []
  207.         for b in self.getBlocks():
  208.             l.extend(b.getContainedGraphs())
  209.         
  210.         return l
  211.  
  212.  
  213.  
  214. def dfs_postorder(b, seen):
  215.     '''Depth-first search of tree rooted at b, return in postorder'''
  216.     order = []
  217.     seen[b] = b
  218.     for c in b.get_children():
  219.         if seen.has_key(c):
  220.             continue
  221.         
  222.         order = order + dfs_postorder(c, seen)
  223.     
  224.     order.append(b)
  225.     return order
  226.  
  227.  
  228. class Block:
  229.     _count = 0
  230.     
  231.     def __init__(self, label = ''):
  232.         self.insts = []
  233.         self.inEdges = misc.Set()
  234.         self.outEdges = misc.Set()
  235.         self.label = label
  236.         self.bid = Block._count
  237.         self.next = []
  238.         Block._count = Block._count + 1
  239.  
  240.     
  241.     def __repr__(self):
  242.         if self.label:
  243.             return '<block %s id=%d>' % (self.label, self.bid)
  244.         else:
  245.             return '<block id=%d>' % self.bid
  246.  
  247.     
  248.     def __str__(self):
  249.         insts = map(str, self.insts)
  250.         return '<block %s %d:\n%s>' % (self.label, self.bid, '\n'.join(insts))
  251.  
  252.     
  253.     def emit(self, inst):
  254.         op = inst[0]
  255.         if op[:4] == 'JUMP':
  256.             self.outEdges.add(inst[1])
  257.         
  258.         self.insts.append(inst)
  259.  
  260.     
  261.     def getInstructions(self):
  262.         return self.insts
  263.  
  264.     
  265.     def addInEdge(self, block):
  266.         self.inEdges.add(block)
  267.  
  268.     
  269.     def addOutEdge(self, block):
  270.         self.outEdges.add(block)
  271.  
  272.     
  273.     def addNext(self, block):
  274.         self.next.append(block)
  275.  
  276.     _uncond_transfer = ('RETURN_VALUE', 'RAISE_VARARGS', 'YIELD_VALUE', 'JUMP_ABSOLUTE', 'JUMP_FORWARD', 'CONTINUE_LOOP')
  277.     
  278.     def pruneNext(self):
  279.         """Remove bogus edge for unconditional transfers
  280.  
  281.         Each block has a next edge that accounts for implicit control
  282.         transfers, e.g. from a JUMP_IF_FALSE to the block that will be
  283.         executed if the test is true.
  284.  
  285.         These edges must remain for the current assembler code to
  286.         work. If they are removed, the dfs_postorder gets things in
  287.         weird orders.  However, they shouldn't be there for other
  288.         purposes, e.g. conversion to SSA form.  This method will
  289.         remove the next edge when it follows an unconditional control
  290.         transfer.
  291.         """
  292.         
  293.         try:
  294.             (op, arg) = self.insts[-1]
  295.         except (IndexError, ValueError):
  296.             return None
  297.  
  298.         if op in self._uncond_transfer:
  299.             self.next = []
  300.         
  301.  
  302.     
  303.     def get_children(self):
  304.         if self.next and self.next[0] in self.outEdges:
  305.             self.outEdges.remove(self.next[0])
  306.         
  307.         return self.outEdges.elements() + self.next
  308.  
  309.     
  310.     def getContainedGraphs(self):
  311.         '''Return all graphs contained within this block.
  312.  
  313.         For example, a MAKE_FUNCTION block will contain a reference to
  314.         the graph for the function body.
  315.         '''
  316.         contained = []
  317.         for inst in self.insts:
  318.             if len(inst) == 1:
  319.                 continue
  320.             
  321.             op = inst[1]
  322.             if hasattr(op, 'graph'):
  323.                 contained.append(op.graph)
  324.                 continue
  325.         
  326.         return contained
  327.  
  328.  
  329. RAW = 'RAW'
  330. FLAT = 'FLAT'
  331. CONV = 'CONV'
  332. DONE = 'DONE'
  333.  
  334. class PyFlowGraph(FlowGraph):
  335.     super_init = FlowGraph.__init__
  336.     
  337.     def __init__(self, name, filename, args = (), optimized = 0, klass = None):
  338.         self.super_init()
  339.         self.name = name
  340.         self.filename = filename
  341.         self.docstring = None
  342.         self.args = args
  343.         self.argcount = getArgCount(args)
  344.         self.klass = klass
  345.         if optimized:
  346.             self.flags = CO_OPTIMIZED | CO_NEWLOCALS
  347.         else:
  348.             self.flags = 0
  349.         self.consts = []
  350.         self.names = []
  351.         self.freevars = []
  352.         self.cellvars = []
  353.         self.closure = []
  354.         if not list(args):
  355.             pass
  356.         self.varnames = []
  357.         for i in range(len(self.varnames)):
  358.             var = self.varnames[i]
  359.             if isinstance(var, TupleArg):
  360.                 self.varnames[i] = var.getName()
  361.                 continue
  362.         
  363.         self.stage = RAW
  364.  
  365.     
  366.     def setDocstring(self, doc):
  367.         self.docstring = doc
  368.  
  369.     
  370.     def setFlag(self, flag):
  371.         self.flags = self.flags | flag
  372.         if flag == CO_VARARGS:
  373.             self.argcount = self.argcount - 1
  374.         
  375.  
  376.     
  377.     def checkFlag(self, flag):
  378.         if self.flags & flag:
  379.             return 1
  380.         
  381.  
  382.     
  383.     def setFreeVars(self, names):
  384.         self.freevars = list(names)
  385.  
  386.     
  387.     def setCellVars(self, names):
  388.         self.cellvars = names
  389.  
  390.     
  391.     def getCode(self):
  392.         '''Get a Python code object'''
  393.         if self.stage == RAW:
  394.             self.computeStackDepth()
  395.             self.flattenGraph()
  396.         
  397.         if self.stage == FLAT:
  398.             self.convertArgs()
  399.         
  400.         if self.stage == CONV:
  401.             self.makeByteCode()
  402.         
  403.         if self.stage == DONE:
  404.             return self.newCodeObject()
  405.         
  406.         raise RuntimeError, 'inconsistent PyFlowGraph state'
  407.  
  408.     
  409.     def dump(self, io = None):
  410.         if io:
  411.             save = sys.stdout
  412.             sys.stdout = io
  413.         
  414.         pc = 0
  415.         for t in self.insts:
  416.             opname = t[0]
  417.             if opname == 'SET_LINENO':
  418.                 print 
  419.             
  420.             if len(t) == 1:
  421.                 print '\t', '%3d' % pc, opname
  422.                 pc = pc + 1
  423.                 continue
  424.             print '\t', '%3d' % pc, opname, t[1]
  425.             pc = pc + 3
  426.         
  427.         if io:
  428.             sys.stdout = save
  429.         
  430.  
  431.     
  432.     def computeStackDepth(self):
  433.         '''Compute the max stack depth.
  434.  
  435.         Approach is to compute the stack effect of each basic block.
  436.         Then find the path through the code with the largest total
  437.         effect.
  438.         '''
  439.         depth = { }
  440.         exit = None
  441.         for b in self.getBlocks():
  442.             depth[b] = findDepth(b.getInstructions())
  443.         
  444.         seen = { }
  445.         
  446.         def max_depth(b, d):
  447.             if seen.has_key(b):
  448.                 return d
  449.             
  450.             seen[b] = 1
  451.             d = d + depth[b]
  452.             children = b.get_children()
  453.             if children:
  454.                 return []([ max_depth(c, d) for c in children ])
  455.             elif not b.label == 'exit':
  456.                 return max_depth(self.exit, d)
  457.             else:
  458.                 return d
  459.  
  460.         self.stacksize = max_depth(self.entry, 0)
  461.  
  462.     
  463.     def flattenGraph(self):
  464.         '''Arrange the blocks in order and resolve jumps'''
  465.         self.insts = insts = []
  466.         pc = 0
  467.         begin = { }
  468.         end = { }
  469.         for b in self.getBlocksInOrder():
  470.             begin[b] = pc
  471.             for inst in b.getInstructions():
  472.                 insts.append(inst)
  473.                 if len(inst) == 1:
  474.                     pc = pc + 1
  475.                     continue
  476.                 if inst[0] != 'SET_LINENO':
  477.                     pc = pc + 3
  478.                     continue
  479.             
  480.             end[b] = pc
  481.         
  482.         pc = 0
  483.         for i in range(len(insts)):
  484.             inst = insts[i]
  485.             if len(inst) == 1:
  486.                 pc = pc + 1
  487.             elif inst[0] != 'SET_LINENO':
  488.                 pc = pc + 3
  489.             
  490.             opname = inst[0]
  491.             if self.hasjrel.has_elt(opname):
  492.                 oparg = inst[1]
  493.                 offset = begin[oparg] - pc
  494.                 insts[i] = (opname, offset)
  495.                 continue
  496.             if self.hasjabs.has_elt(opname):
  497.                 insts[i] = (opname, begin[inst[1]])
  498.                 continue
  499.         
  500.         self.stage = FLAT
  501.  
  502.     hasjrel = misc.Set()
  503.     for i in dis.hasjrel:
  504.         hasjrel.add(dis.opname[i])
  505.     
  506.     hasjabs = misc.Set()
  507.     for i in dis.hasjabs:
  508.         hasjabs.add(dis.opname[i])
  509.     
  510.     
  511.     def convertArgs(self):
  512.         '''Convert arguments from symbolic to concrete form'''
  513.         self.consts.insert(0, self.docstring)
  514.         self.sort_cellvars()
  515.         for i in range(len(self.insts)):
  516.             t = self.insts[i]
  517.             if len(t) == 2:
  518.                 (opname, oparg) = t
  519.                 conv = self._converters.get(opname, None)
  520.                 if conv:
  521.                     self.insts[i] = (opname, conv(self, oparg))
  522.                 
  523.             conv
  524.         
  525.         self.stage = CONV
  526.  
  527.     
  528.     def sort_cellvars(self):
  529.         '''Sort cellvars in the order of varnames and prune from freevars.
  530.         '''
  531.         cells = { }
  532.         for name in self.cellvars:
  533.             cells[name] = 1
  534.         
  535.         self.cellvars = _[1]
  536.         for name in self.cellvars:
  537.             del cells[name]
  538.         
  539.         self.cellvars = self.cellvars + cells.keys()
  540.         self.closure = self.cellvars + self.freevars
  541.  
  542.     
  543.     def _lookupName(self, name, list):
  544.         """Return index of name in list, appending if necessary
  545.  
  546.         This routine uses a list instead of a dictionary, because a
  547.         dictionary can't store two different keys if the keys have the
  548.         same value but different types, e.g. 2 and 2L.  The compiler
  549.         must treat these two separately, so it does an explicit type
  550.         comparison before comparing the values.
  551.         """
  552.         t = type(name)
  553.         for i in range(len(list)):
  554.             if t == type(list[i]) and list[i] == name:
  555.                 return i
  556.                 continue
  557.         
  558.         end = len(list)
  559.         list.append(name)
  560.         return end
  561.  
  562.     _converters = { }
  563.     
  564.     def _convert_LOAD_CONST(self, arg):
  565.         if hasattr(arg, 'getCode'):
  566.             arg = arg.getCode()
  567.         
  568.         return self._lookupName(arg, self.consts)
  569.  
  570.     
  571.     def _convert_LOAD_FAST(self, arg):
  572.         self._lookupName(arg, self.names)
  573.         return self._lookupName(arg, self.varnames)
  574.  
  575.     _convert_STORE_FAST = _convert_LOAD_FAST
  576.     _convert_DELETE_FAST = _convert_LOAD_FAST
  577.     
  578.     def _convert_LOAD_NAME(self, arg):
  579.         if self.klass is None:
  580.             self._lookupName(arg, self.varnames)
  581.         
  582.         return self._lookupName(arg, self.names)
  583.  
  584.     
  585.     def _convert_NAME(self, arg):
  586.         if self.klass is None:
  587.             self._lookupName(arg, self.varnames)
  588.         
  589.         return self._lookupName(arg, self.names)
  590.  
  591.     _convert_STORE_NAME = _convert_NAME
  592.     _convert_DELETE_NAME = _convert_NAME
  593.     _convert_IMPORT_NAME = _convert_NAME
  594.     _convert_IMPORT_FROM = _convert_NAME
  595.     _convert_STORE_ATTR = _convert_NAME
  596.     _convert_LOAD_ATTR = _convert_NAME
  597.     _convert_DELETE_ATTR = _convert_NAME
  598.     _convert_LOAD_GLOBAL = _convert_NAME
  599.     _convert_STORE_GLOBAL = _convert_NAME
  600.     _convert_DELETE_GLOBAL = _convert_NAME
  601.     
  602.     def _convert_DEREF(self, arg):
  603.         self._lookupName(arg, self.names)
  604.         self._lookupName(arg, self.varnames)
  605.         return self._lookupName(arg, self.closure)
  606.  
  607.     _convert_LOAD_DEREF = _convert_DEREF
  608.     _convert_STORE_DEREF = _convert_DEREF
  609.     
  610.     def _convert_LOAD_CLOSURE(self, arg):
  611.         self._lookupName(arg, self.varnames)
  612.         return self._lookupName(arg, self.closure)
  613.  
  614.     _cmp = list(dis.cmp_op)
  615.     
  616.     def _convert_COMPARE_OP(self, arg):
  617.         return self._cmp.index(arg)
  618.  
  619.     for name, obj in locals().items():
  620.         if name[:9] == '_convert_':
  621.             opname = name[9:]
  622.             _converters[opname] = obj
  623.             continue
  624.     
  625.     del name
  626.     del obj
  627.     del opname
  628.     
  629.     def makeByteCode(self):
  630.         self.lnotab = lnotab = LineAddrTable()
  631.         for t in self.insts:
  632.             opname = t[0]
  633.             if len(t) == 1:
  634.                 lnotab.addCode(self.opnum[opname])
  635.                 continue
  636.             oparg = t[1]
  637.             if opname == 'SET_LINENO':
  638.                 lnotab.nextLine(oparg)
  639.                 continue
  640.             
  641.             (hi, lo) = twobyte(oparg)
  642.             
  643.             try:
  644.                 lnotab.addCode(self.opnum[opname], lo, hi)
  645.             continue
  646.             except ValueError:
  647.                 print opname, oparg
  648.                 print self.opnum[opname], lo, hi
  649.                 raise 
  650.                 continue
  651.             
  652.  
  653.         
  654.         self.stage = DONE
  655.  
  656.     opnum = { }
  657.     for num in range(len(dis.opname)):
  658.         opnum[dis.opname[num]] = num
  659.     
  660.     del num
  661.     
  662.     def newCodeObject(self):
  663.         if self.flags & CO_NEWLOCALS == 0:
  664.             nlocals = 0
  665.         else:
  666.             nlocals = len(self.varnames)
  667.         argcount = self.argcount
  668.         if self.flags & CO_VARKEYWORDS:
  669.             argcount = argcount - 1
  670.         
  671.         return new.code(argcount, nlocals, self.stacksize, self.flags, self.lnotab.getCode(), self.getConsts(), tuple(self.names), tuple(self.varnames), self.filename, self.name, self.lnotab.firstline, self.lnotab.getTable(), tuple(self.freevars), tuple(self.cellvars))
  672.  
  673.     
  674.     def getConsts(self):
  675.         '''Return a tuple for the const slot of the code object
  676.  
  677.         Must convert references to code (MAKE_FUNCTION) to code
  678.         objects recursively.
  679.         '''
  680.         l = []
  681.         for elt in self.consts:
  682.             if isinstance(elt, PyFlowGraph):
  683.                 elt = elt.getCode()
  684.             
  685.             l.append(elt)
  686.         
  687.         return tuple(l)
  688.  
  689.  
  690.  
  691. def isJump(opname):
  692.     if opname[:4] == 'JUMP':
  693.         return 1
  694.     
  695.  
  696.  
  697. class TupleArg:
  698.     '''Helper for marking func defs with nested tuples in arglist'''
  699.     
  700.     def __init__(self, count, names):
  701.         self.count = count
  702.         self.names = names
  703.  
  704.     
  705.     def __repr__(self):
  706.         return 'TupleArg(%s, %s)' % (self.count, self.names)
  707.  
  708.     
  709.     def getName(self):
  710.         return '.%d' % self.count
  711.  
  712.  
  713.  
  714. def getArgCount(args):
  715.     argcount = len(args)
  716.     if args:
  717.         for arg in args:
  718.             if isinstance(arg, TupleArg):
  719.                 numNames = len(misc.flatten(arg.names))
  720.                 argcount = argcount - numNames
  721.                 continue
  722.         
  723.     
  724.     return argcount
  725.  
  726.  
  727. def twobyte(val):
  728.     '''Convert an int argument into high and low bytes'''
  729.     return divmod(val, 256)
  730.  
  731.  
  732. class LineAddrTable:
  733.     """lnotab
  734.  
  735.     This class builds the lnotab, which is documented in compile.c.
  736.     Here's a brief recap:
  737.  
  738.     For each SET_LINENO instruction after the first one, two bytes are
  739.     added to lnotab.  (In some cases, multiple two-byte entries are
  740.     added.)  The first byte is the distance in bytes between the
  741.     instruction for the last SET_LINENO and the current SET_LINENO.
  742.     The second byte is offset in line numbers.  If either offset is
  743.     greater than 255, multiple two-byte entries are added -- see
  744.     compile.c for the delicate details.
  745.     """
  746.     
  747.     def __init__(self):
  748.         self.code = []
  749.         self.codeOffset = 0
  750.         self.firstline = 0
  751.         self.lastline = 0
  752.         self.lastoff = 0
  753.         self.lnotab = []
  754.  
  755.     
  756.     def addCode(self, *args):
  757.         for arg in args:
  758.             self.code.append(chr(arg))
  759.         
  760.         self.codeOffset = self.codeOffset + len(args)
  761.  
  762.     
  763.     def nextLine(self, lineno):
  764.         if self.firstline == 0:
  765.             self.firstline = lineno
  766.             self.lastline = lineno
  767.         else:
  768.             addr = self.codeOffset - self.lastoff
  769.             line = lineno - self.lastline
  770.             if line >= 0:
  771.                 push = self.lnotab.append
  772.                 while addr > 255:
  773.                     push(255)
  774.                     push(0)
  775.                     addr -= 255
  776.                 while line > 255:
  777.                     push(addr)
  778.                     push(255)
  779.                     line -= 255
  780.                     addr = 0
  781.                 if addr > 0 or line > 0:
  782.                     push(addr)
  783.                     push(line)
  784.                 
  785.                 self.lastline = lineno
  786.                 self.lastoff = self.codeOffset
  787.             
  788.  
  789.     
  790.     def getCode(self):
  791.         return ''.join(self.code)
  792.  
  793.     
  794.     def getTable(self):
  795.         return ''.join(map(chr, self.lnotab))
  796.  
  797.  
  798.  
  799. class StackDepthTracker:
  800.     
  801.     def findDepth(self, insts, debug = 0):
  802.         depth = 0
  803.         maxDepth = 0
  804.         for i in insts:
  805.             opname = i[0]
  806.             if debug:
  807.                 print i,
  808.             
  809.             delta = self.effect.get(opname, None)
  810.             if delta is not None:
  811.                 depth = depth + delta
  812.             else:
  813.                 for pat, pat_delta in self.patterns:
  814.                     if opname[:len(pat)] == pat:
  815.                         delta = pat_delta
  816.                         depth = depth + delta
  817.                         break
  818.                         continue
  819.                 
  820.                 if delta is None:
  821.                     meth = getattr(self, opname, None)
  822.                     if meth is not None:
  823.                         depth = depth + meth(i[1])
  824.                     
  825.                 
  826.             if depth > maxDepth:
  827.                 maxDepth = depth
  828.             
  829.             if debug:
  830.                 print depth, maxDepth
  831.                 continue
  832.         
  833.         return maxDepth
  834.  
  835.     effect = {
  836.         'POP_TOP': -1,
  837.         'DUP_TOP': 1,
  838.         'SLICE+1': -1,
  839.         'SLICE+2': -1,
  840.         'SLICE+3': -2,
  841.         'STORE_SLICE+0': -1,
  842.         'STORE_SLICE+1': -2,
  843.         'STORE_SLICE+2': -2,
  844.         'STORE_SLICE+3': -3,
  845.         'DELETE_SLICE+0': -1,
  846.         'DELETE_SLICE+1': -2,
  847.         'DELETE_SLICE+2': -2,
  848.         'DELETE_SLICE+3': -3,
  849.         'STORE_SUBSCR': -3,
  850.         'DELETE_SUBSCR': -2,
  851.         'PRINT_ITEM': -1,
  852.         'RETURN_VALUE': -1,
  853.         'YIELD_VALUE': -1,
  854.         'EXEC_STMT': -3,
  855.         'BUILD_CLASS': -2,
  856.         'STORE_NAME': -1,
  857.         'STORE_ATTR': -2,
  858.         'DELETE_ATTR': -1,
  859.         'STORE_GLOBAL': -1,
  860.         'BUILD_MAP': 1,
  861.         'COMPARE_OP': -1,
  862.         'STORE_FAST': -1,
  863.         'IMPORT_STAR': -1,
  864.         'IMPORT_NAME': 0,
  865.         'IMPORT_FROM': 1,
  866.         'LOAD_ATTR': 0,
  867.         'SETUP_EXCEPT': 3,
  868.         'SETUP_FINALLY': 3,
  869.         'FOR_ITER': 1 }
  870.     patterns = [
  871.         ('BINARY_', -1),
  872.         ('LOAD_', 1)]
  873.     
  874.     def UNPACK_SEQUENCE(self, count):
  875.         return count - 1
  876.  
  877.     
  878.     def BUILD_TUPLE(self, count):
  879.         return -count + 1
  880.  
  881.     
  882.     def BUILD_LIST(self, count):
  883.         return -count + 1
  884.  
  885.     
  886.     def CALL_FUNCTION(self, argc):
  887.         (hi, lo) = divmod(argc, 256)
  888.         return -(lo + hi * 2)
  889.  
  890.     
  891.     def CALL_FUNCTION_VAR(self, argc):
  892.         return self.CALL_FUNCTION(argc) - 1
  893.  
  894.     
  895.     def CALL_FUNCTION_KW(self, argc):
  896.         return self.CALL_FUNCTION(argc) - 1
  897.  
  898.     
  899.     def CALL_FUNCTION_VAR_KW(self, argc):
  900.         return self.CALL_FUNCTION(argc) - 2
  901.  
  902.     
  903.     def MAKE_FUNCTION(self, argc):
  904.         return -argc
  905.  
  906.     
  907.     def MAKE_CLOSURE(self, argc):
  908.         return -argc
  909.  
  910.     
  911.     def BUILD_SLICE(self, argc):
  912.         if argc == 2:
  913.             return -1
  914.         elif argc == 3:
  915.             return -2
  916.         
  917.  
  918.     
  919.     def DUP_TOPX(self, argc):
  920.         return argc
  921.  
  922.  
  923. findDepth = StackDepthTracker().findDepth
  924.